package cn.com.mjsoft.framework.exception;

import java.io.PrintStream;
import java.io.PrintWriter;

/**
 * 
 * @author mjsoft
 * 
 */

public abstract class NestedRuntimeException extends RuntimeException
{

    private static final long serialVersionUID = 1976426891338818697L;
    /** Root cause of this nested exception */
    private Throwable cause;

    public NestedRuntimeException( Throwable cause )
    {
        super( cause );

    }

    public NestedRuntimeException( String msg )
    {
        super( msg );
    }

    public NestedRuntimeException( String msg, Throwable cause )
    {
        super( msg );
        this.cause = cause;
    }

    public Throwable getCause()
    {
        return ( this.cause == this ? null : this.cause );
    }

    public String getMessage()
    {
        return NestedExceptionUtils.buildMessage( super.getMessage(), getCause() );
    }

    public void printStackTrace( PrintStream ps )
    {
        if( getCause() == null )
        {
            super.printStackTrace( ps );
        }
        else
        {
            ps.println( this );
            ps.print( "Caused by: " );
            getCause().printStackTrace( ps );
        }
    }

    public void printStackTrace( PrintWriter pw )
    {
        if( getCause() == null )
        {
            super.printStackTrace( pw );
        }
        else
        {
            pw.println( this );
            pw.print( "Caused by: " );
            getCause().printStackTrace( pw );
        }
    }

    public Throwable getRootCause()
    {
        Throwable cause = getCause();
        if( cause instanceof NestedRuntimeException )
        {
            return ( ( NestedRuntimeException ) cause ).getRootCause();
        }
        else
        {
            return cause;
        }
    }

    public boolean contains( Class<?> exClass )
    {
        if( exClass == null )
        {
            return false;
        }
        if( exClass.isInstance( this ) )
        {
            return true;
        }
        Throwable cause = getCause();
        if( cause instanceof NestedRuntimeException )
        {
            return ( ( NestedRuntimeException ) cause ).contains( exClass );
        }
        else
        {
            return ( cause != null && exClass.isInstance( cause ) );
        }
    }

}
